/*
* // +-------------------------------------------------------------------------------------------------
* // |                 有你就好 [ 有节骨乃坚，无心品自端 ]     <http://encoding.wang>
* // +-------------------------------------------------------------------------------------------------
* // |                             独在异乡为异客         每逢佳节倍思亲
* // +-------------------------------------------------------------------------------------------------
* // |                 联系:   <707069100@qq.com>      <http://weibo.com/513778937>
* // +-------------------------------------------------------------------------------------------------
*/

// -----------------------------------------------------------------------------------------------------
// +----------------------------------------------------------------------------------------------------
// |                   ErYang出品 属于小极品          共同学习    共同进步
// +----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------

package wang.encoding.mroot.admin.controller.login


import org.apache.shiro.SecurityUtils
import org.apache.shiro.authc.*
import org.apache.shiro.subject.Subject
import org.apache.shiro.web.util.SavedRequest
import org.apache.shiro.web.util.WebUtils
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.servlet.ModelAndView
import wang.encoding.mroot.admin.common.controller.BaseAdminController
import wang.encoding.mroot.admin.common.util.ShiroSessionUtil
import wang.encoding.mroot.common.annotation.FormToken
import wang.encoding.mroot.common.annotation.RequestLogAnnotation
import wang.encoding.mroot.common.business.ResultData
import wang.encoding.mroot.common.constant.RequestLogConstant
import wang.encoding.mroot.common.exception.ControllerException
import wang.encoding.mroot.common.util.RegexUtil
import wang.encoding.mroot.service.system.UserService
import javax.servlet.http.HttpServletRequest

/**
 * 登录控制器
 *
 * @author ErYang
 */
@RestController
class LoginController : BaseAdminController() {

    companion object {

        /**
         * logger
         */
        private val logger: Logger = LoggerFactory.getLogger(LoginController::class.java)

        /**
         * 登录 url
         */
        private const val LOGIN_URL = "/login"

        /**
         * 处理登录 url
         */
        private const val DO_LOGIN_URL = "/doLogin"

        /**
         * 登录页面
         */
        private const val LOGIN_VIEW = "/login/login"
        /**
         * 登录页面 开发环境
         */
        private const val DEV_LOGIN_VIEW = "/login/login2Dev"

        /**
         * 退出 url
         */
        private const val LOGOUT_URL = "/logout"

    }

    // -------------------------------------------------------------------------------------------------

    @Autowired
    private lateinit var userService: UserService

    // -------------------------------------------------------------------------------------------------

    /**
     * 登录页面
     *
     * @return ModelAndView
     */
    @RequestLogAnnotation(module = RequestLogConstant.ADMIN_MODULE, title = RequestLogConstant.ADMIN_MODULE_LOGIN_VIEW)
    @RequestMapping(LOGIN_URL)
    @FormToken(init = true)
    @Throws(ControllerException::class)
    fun index(): ModelAndView {
        val modelAndView = ModelAndView()
        if (this.validationVerifyCode()) {
            modelAndView.addObject("isVerifyCode", "show")
        } else {
            modelAndView.addObject("isVerifyCode", "hide")
        }
        // 开发环境
        return if (super.devProfile()) {
            modelAndView.viewName = super.initView(DEV_LOGIN_VIEW)
            modelAndView
        } else {
            modelAndView.viewName = super.initView(LOGIN_VIEW)
            modelAndView
        }
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 处理登录
     *
     * @param request HttpServletRequest
     * @return JSONObject
     */
    @RequestMapping(DO_LOGIN_URL)
    @ResponseBody
    @RequestLogAnnotation(module = RequestLogConstant.ADMIN_MODULE,
            title = RequestLogConstant.ADMIN_MODULE_LOGIN_DO_LOGIN)
    @FormToken(remove = true)
    @Throws(ControllerException::class)
    fun login(request: HttpServletRequest): Any {
        if (super.isAjaxRequest(request)) {
            var result: ResultData
            val username: String? = request.getParameter("username")
            val password: String? = request.getParameter("password")
            val verifyCode: String? = request.getParameter("verifyCode")
            // 验证数据
            result = this.validationData(request, username, password, verifyCode)
            if (result.isFail!!) {
                // 生成 token 并放入 session 中
                super.initJSONObjectTokenValue(result)
                return result.toFastJson()
            }
            // Shiro 验证
            val usernamePasswordToken = UsernamePasswordToken(username, password)
            val subject: Subject = SecurityUtils.getSubject()

            try {
                subject.login(usernamePasswordToken)
            } catch (uae: UnknownAccountException) {
                if (logger.isErrorEnabled) {
                    logger.error(">>>>>用户[$username]进行登录验证...验证未通过,未知账户<<<<<")
                }
                result.setFail()[configProperties.messageName] = localeMessageSourceConfiguration.getMessage("message.user.login.error")
            } catch (ice: IncorrectCredentialsException) {
                if (logger.isErrorEnabled) {
                    logger.error(">>>>>用户[$username]进行登录验证...验证未通过,错误的凭证<<<<<")
                }
                result.setFail()[configProperties.messageName] = localeMessageSourceConfiguration.getMessage("message.user.login.error")
            } catch (lae: LockedAccountException) {
                if (logger.isErrorEnabled) {
                    logger.error(">>>>>用户[$username]进行登录验证...验证未通过,账户已锁定<<<<<")
                }
                result.setFail()[configProperties.messageName] = localeMessageSourceConfiguration.getMessage("message.user.login.error")
            } catch (eae: ExcessiveAttemptsException) {
                if (logger.isErrorEnabled) {
                    logger.error(">>>>>用户[$username]进行登录验证...验证未通过,错误次数过多<<<<<")
                }
                result.setFail()[configProperties.messageName] = localeMessageSourceConfiguration.getMessage("message.user.login.error")
            } catch (ae: AuthenticationException) {
                if (logger.isErrorEnabled) {
                    // 通过处理 Shiro 的运行时 AuthenticationException 就可以控制用户登录失败或密码错误时的情景
                    logger.error(">>>>>用户[$username]进行登录验证...验证未通过,堆栈轨迹如下<<<<<")
                }
                ae.printStackTrace()
                result.setFail()[configProperties.messageName] = localeMessageSourceConfiguration.getMessage("message.user.login.error")
            }

            // 验证通过
            if (subject.isAuthenticated) {
                if (this.validationVerifyCode()) {
                    ShiroSessionUtil.setAttribute("isVerifyCode", "hide")
                }
                result = userService.login(username?.trim()!!.toLowerCase(),
                        digestManageConfiguration.getSha512(password?.trim()!!))
                if (result.isOk!!) {
                    // 利用 shiro 跳转到登录前的页面
                    val savedRequest: SavedRequest? = WebUtils.getSavedRequest(request)
                    // 获取保存的URL
                    if (null == savedRequest || savedRequest.requestUrl.isEmpty()) run {
                        result["url"] = initUrl("index")
                    } else {
                        val uri: String = savedRequest.requestUrl
                        if (super.contextPath == uri || super.contextPath + "/" == uri ||
                                uri.contains(configProperties.adminLogoutUrlName) || uri.contains("null")) {
                            result["url"] = initUrl("index")
                        } else {
                            result["url"] = initUrl(uri.removePrefix(super.contextPath + "/"))
                        }
                    }
                }
            } else {
                // 生成 isVerifyCode 并放入 session 中
                ShiroSessionUtil.setAttribute("isVerifyCode", "show")
                result.setFail()["isVerifyCode"] = "show"
                super.initJSONObjectTokenValue(result)
            }
            return result.toFastJson()
        } else {
            return super.initErrorRedirectUrl()
        }
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 退出登录
     *
     * @return
     */
    @RequestMapping(LOGOUT_URL)
    @RequestLogAnnotation(module = RequestLogConstant.ADMIN_MODULE,
            title = RequestLogConstant.ADMIN_MODULE_LOGOUT)
    @Throws(ControllerException::class)
    fun logout(): ModelAndView {
        // shiro 管理的 session
        ShiroSessionUtil.removeAttribute(configProperties.adminSessionName)
        ShiroSessionUtil.removeAttribute(configProperties.adminMenuName)
        // shiro 销毁登录
        val subject: Subject = SecurityUtils.getSubject()
        subject.logout()
        val modelAndView = ModelAndView()
        modelAndView.viewName = super.initRedirectUrl(LOGIN_URL)
        return modelAndView
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 验证数据 数据的唯一性
     *
     * @param request         HttpServletRequest
     * @param username         String
     * @param password         String
     * @param verifyCode         String
     *
     * @return ResultData
     */
    private fun validationData(request: HttpServletRequest, username: String?,
                               password: String?, verifyCode: String?): ResultData {
        val result: ResultData
        if (null != username && null != password) {
            // 检验验证码
            if (!super.devProfile()) {
                if (this.validationVerifyCode()) {
                    if (null == verifyCode || !super.checkKaptcha(verifyCode, request)) {
                        result = ResultData.fail(configProperties.messageName,
                                localeMessageSourceConfiguration.getMessage("message.user.verifyCode.error"))
                        return result
                    }
                }
            }
            // 用户名有效性
            val usernameFlag: Boolean = RegexUtil.regexValidate(username.trim(),
                    RegexUtil.CN_LETTER_NUM_UL_5TO18_REGEX)
            if (!usernameFlag) {
                result = ResultData.fail(configProperties.messageName,
                        localeMessageSourceConfiguration.getMessage("message.user.login.error"))
                return result
            }

            // 密码有效性
            val passwordFlag: Boolean = RegexUtil.regexValidate(password.trim(),
                    RegexUtil.LETTER_NUM_6TO18_REGEX)
            if (!passwordFlag) {
                result = ResultData.fail(configProperties.messageName,
                        localeMessageSourceConfiguration.getMessage("message.user.login.error"))
                return result
            }

        } else {
            result = ResultData.fail(configProperties.messageName,
                    localeMessageSourceConfiguration.getMessage("message.user.login.error"))
            return result
        }
        return ResultData.ok()
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 检验是否需要验证码
     *
     * @return  Boolean
     */
    protected fun validationVerifyCode(): Boolean {
        val isVerifyCode: String? = ShiroSessionUtil.getAttribute("isVerifyCode") as String?
        return !(null == isVerifyCode || "show" != isVerifyCode)
    }

    // -------------------------------------------------------------------------------------------------

}

// -----------------------------------------------------------------------------------------------------

// End LoginController class

/* End of file LoginController.kt */
/* Location: ./src/main/kotlin/wang/encoding/mroot/admin/controller/login/LoginController.kt */

// -----------------------------------------------------------------------------------------------------
// +----------------------------------------------------------------------------------------------------
// |                           ErYang出品 属于小极品  O(∩_∩)O~~   共同学习    共同进步
// +----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------
